package myJs.tool

import myJs.FileSaver
import myJs.Utils.layer
import myJs.myPkg.jquery.{$, JQuery}
import myJs.myPkg.{LayerOptions, Typeahead}
import org.scalajs.dom.ext.Ajax
import org.scalajs.dom.raw.{Blob, BlobPropertyBag}
import org.scalajs.dom.{Element, window}
import scalatags.Text.all._

import scala.collection.immutable.SeqMap
import scala.concurrent.Future
import scala.scalajs.js
import scala.scalajs.js.JSON
import scala.scalajs.js.annotation.{JSExport, JSExportTopLevel}
import scala.scalajs.js.typedarray.Uint8Array
import scala.concurrent.ExecutionContext.Implicits.global
import myJs.Implicits._
import myJs.tool.Pojo.TextData
import shared.VarTool

import js.Dynamic.{global => g}
import scala.scalajs.js.JSConverters._

/**
 * Created by yz on 2019/3/6
 */
@JSExportTopLevel("Tool")
object Tool {

  val zhInfo = "Info"
  val layerOptions = LayerOptions.title(zhInfo).closeBtn(0).skin("layui-layer-molv").btn(js.Array())
  val junctionTypeAbbrMap = SeqMap("Linear" -> "ls", "Back-splice" -> "bs", "Fusion" -> "fs")
  val decDigits = 3
  val dataBasicType = "data-basic-type"


  val zhRunning = "正在运行"
  val myElement = div(id := "content")(
    span(id := "info")(zhRunning),
    " ",
    img(src := "/assets/images/running2.gif", width := 30, height := 20, cls := "runningImage")
  ).render

  val pattern = "yyyy-mm-dd"

  def element(info: String) = {
    div(id := "content",
      span(id := "info", info,
        span(id := "progress", "")), " ",
      img(src := "/assets/images/running2.gif", width := 30, height := 20, cls := "runningImage")
    ).render
  }

  def selectTab(tabId: String) = {
    $(".myMainUl >li").removeClass("active")
    $(s".myMainUl").find(s"a[href='#${tabId}']").parent("li").addClass("active")
    $(s"#${tabId}").siblings().removeClass("active in")
    $(s"#${tabId}").addClass("active in")
  }

  def downloadCsv(fileName: String, content: js.Any) = {
    val blob = new Blob(js.Array(content), BlobPropertyBag(`type` = "text/csv;charset=utf-8"))
    FileSaver.saveAs(blob, fileName)
  }

  def useLoadingF(showLoading: Boolean = true)(f: () => Future[Any]) = {
    val index = if (showLoading) {
      layer.alert(Tool.loadingElement, Tool.layerOptions)
    } else 0
    f().map { x =>
      if (showLoading) {
        layer.close(index)
      }
    }
  }

  val updater = (y: Typeahead, item: String) => {
    s"${y.$element.`val`().toString.replaceAll("[^,]*$", "")}${item},"
  }

  val singleUpdater = (y: Typeahead, item: String) => {
    s"${y.$element.`val`().toString.replaceAll("[^,]*$", "")}${item}"
  }

  val matcher = (y: Typeahead, item: String) => {
    val tquery = extractor(y.query)
    ~(item.toLowerCase.indexOf(tquery.toLowerCase))
  }

  val highlighterF = (y: Typeahead, item: String) => {
    val input = y.query
    val query = extractor(input).replaceAll("[\\-\\[\\]{}()*+?.,\\\\^$|#\\s]", "\\$&")
    val r = s"(?i)${query}".r
    r.replaceAllIn(item, matcher =>
      s"<strong>${matcher.group(0)}</strong>"
    )
  }

  val loadingElement = element("Running...")

  def extractor(query: String) = {
    val result = js.RegExp("([^,]+)$").exec(query)
    if (result != null && result(1).isDefined) {
      result(1).toString.trim
    } else ""
  }

  @JSExport("downloadImage")
  def downloadImage(y: Element, imageType: String) = {
    val imageJq = $(y).parents(".myCharts").find("img")
    imageType match {
      case "png" => downloadPng(imageJq)
      case "jpeg" => downloadJpeg(imageJq)
      case "pdf" => downloadPdf(imageJq)
      case "svg" => downloadSvg(imageJq)
      case _ => downloadPng(imageJq)
    }
  }

  def downloadSvg(imageJq: JQuery) = {
    val index = layer.alert(Tool.loadingElement, Tool.layerOptions)
    val basicType = imageJq.attr("data-basic-type").getOrElse("pdf")
    val base64 = basicType match {
      case "png" => val src = imageJq.attr("src").get
        src.replaceAll("^data:image/png;base64,", "")
      case "pdf" =>
        imageJq.parent().findInputByName("pdfBase64").myVal
    }
    val url = g.jsRoutes.controllers.ToolController.image2svg().url.toString
    val dict = js.Dictionary("base64" -> base64, "imageType" -> basicType)
    val data = JSON.stringify(dict)
    Ajax.post(url = s"${url}", data = data, headers = Map("Content-Type" -> "application/json"),
      responseType = "application/json").map { xhr =>
      val rs = xhr.responseText.toJDS
      val outBase64 = rs("base64")
      val byteArrays = base642binaryArray(outBase64)
      val fileName = "chart.svg"
      val blob = new Blob(byteArrays, BlobPropertyBag(`type` = "image/svg+xml;charset=utf-8"))
      FileSaver.saveAs(blob, fileName)
      layer.close(index)
    }
  }

  def downloadPdf(imageJq: JQuery) = {
    val basicType = imageJq.attr("data-basic-type").getOrElse("pdf")
    basicType match {
      case "png" => downloadPdfByServer(imageJq)
      case _ => downloadPdfByLocalhost(imageJq)
    }
  }

  def downloadPdfByLocalhost(imageJq: JQuery) = {
    val index = layer.alert(Tool.loadingElement, Tool.layerOptions)
    val outBase64 = imageJq.parent().findInputByName("pdfBase64").myVal
    val byteArrays = base642binaryArray(outBase64)
    val fileName = "chart.pdf"
    val blob = new Blob(byteArrays, BlobPropertyBag(`type` = "application/pdf"))
    FileSaver.saveAs(blob, fileName)
    layer.close(index)
  }

  def downloadPdfByServer(imageJq: JQuery) = {
    val index = layer.alert(Tool.loadingElement, Tool.layerOptions)
    val src = imageJq.attr("src").get
    val base64 = src.replaceAll("^data:image/png;base64,", "")
    val url = g.jsRoutes.controllers.ToolController.png2pdf().url.toString
    val dict = js.Dictionary("base64" -> base64)
    val data = JSON.stringify(dict)
    Ajax.post(url = s"${url}", data = data, headers = Map("Content-Type" -> "application/json"),
      responseType = "application/json").map { xhr =>
      val rs = xhr.responseText.toJDS
      val outBase64 = rs("base64")
      val byteArrays = base642binaryArray(outBase64)
      val fileName = "chart.pdf"
      val blob = new Blob(byteArrays, BlobPropertyBag(`type` = "application/pdf"))
      FileSaver.saveAs(blob, fileName)
      layer.close(index)
    }
  }

  def base642binaryArray(content: String) = {
    val byteCharacters = window.atob(content)
    val sliceSize = 512
    val byteArrays = byteCharacters.grouped(sliceSize).map { slice =>
      val byteNumbers = slice.map(_.toShort).toJSArray
      new Uint8Array(byteNumbers)
    }
    byteArrays.toJSArray.map(_.asInstanceOf[js.Any])
  }

  def downloadPng(imageJq: JQuery) = {
    val index = layer.alert(Tool.loadingElement, Tool.layerOptions)
    val src = imageJq.attr("src").get
    val base64 = src.replaceAll("^data:image/png;base64,", "")
    val byteArrays = base642binaryArray(base64)
    val fileName = "chart.png"
    val blob = new Blob(byteArrays, BlobPropertyBag(`type` = "image/png"))
    FileSaver.saveAs(blob, fileName)
    layer.close(index)
  }

  def downloadJpeg(imageJq: JQuery) = {
    val index = layer.alert(Tool.loadingElement, Tool.layerOptions)
    val src = imageJq.attr("src").get
    val base64 = src.replaceAll("^data:image/png;base64,", "")
    val url = g.jsRoutes.controllers.ToolController.image2jpeg().url.toString
    val dict = js.Dictionary("base64" -> base64, "imageType" -> "png")
    val data = JSON.stringify(dict)
    Ajax.post(url = s"${url}", data = data, headers = Map("Content-Type" -> "application/json"),
      responseType = "application/json").map { xhr =>
      val rs = xhr.responseText.toJDS
      val outBase64 = rs("base64")
      val byteArrays = base642binaryArray(outBase64)
      val fileName = "chart.jpeg"
      val blob = new Blob(byteArrays, BlobPropertyBag(`type` = "image/jpeg"))
      FileSaver.saveAs(blob, fileName)
      layer.close(index)
    }
  }

  @JSExport("expand")
  def expand(y: Element) = {
    val tool = $(y).parent().find(".tools a:last")
    $(tool).click()

  }

  def getInputByName(name: String) = {
    $(s":input[name='${name}']")
  }

  def getInputByName(names: String*) = {
    val namesStr = names.map { name =>
      s":input[name='${name}']"
    }.mkString(",")
    $(s"${namesStr}")
  }

  def getPercent(v: Double) = {
    (v * 100).toInt
  }

  def fillByName(rs: js.Dictionary[String], name: String) = {
    val valOp = rs.get(name)
    valOp.foreach { value =>
      $(s":input[name='${name}']").`val`(value)
    }
  }

  def fillByNames(rs: js.Dictionary[String], names: Seq[String]) = {
    names.foreach { name =>
      fillByName(rs, name)
    }
  }

  def fillByNames(rs: js.Dictionary[String]) = {
    val names = $(".fillByName").mapElems { y =>
      $(y).attr("name").toString
    }.toArray
    names.foreach { name =>
      fillByName(rs, name)
    }
  }


  def checkedByNames(rs: js.Dictionary[String], names: Seq[String]) = {
    names.foreach { name =>
      checkedByName(rs, name)
    }
  }

  def checkedByName(rs: js.Dictionary[String], name: String) = {
    rs.get(name) match {
      case Some(value) => $(s":input[name='${name}']").attr("checked", true)
      case None => $(s":input[name='${name}']").attr("checked", false)
    }
  }

  def fillByNames(rs: js.Dictionary[String], formId: String) = {
    val names = $(s"#${formId} .fillByName").mapElems { y =>
      $(y).attr("name").toString
    }.toArray
    names.foreach { name =>
      fillByName(rs, name, formId)
    }
  }

  def fillByIds(rs: js.Dictionary[String]) = {
    val ids = $(s".fillById").mapElems { y =>
      $(y).attr("id").toString
    }.toArray
    ids.foreach { name =>
      fillById(rs, name)
    }
  }

  def fillByName(rs: js.Dictionary[String], name: String, formId: String) = {
    val value = rs(name)
    $(s"#${formId} :input[name='${name}']").`val`(value)
  }

  def fillById(rs: js.Dictionary[String], id: String) = {
    val value = rs(id)
    $(s"#${id}").text(value)
  }

  def fillByNameAndTriggers(rs: js.Dictionary[String], names: List[String]) = {
    names.foreach { name =>
      fillByNameAndTrigger(rs, name)
    }
  }

  def fillByNameAndTriggers(rs: js.Dictionary[String]) = {
    val names = $(s".fillByNameAndTrigger").mapElems { y =>
      $(y).attr("name").toString
    }.toArray
    names.foreach { name =>
      fillByNameAndTrigger(rs, name)
    }
  }

  def fillByNameAndTrigger(rs: js.Dictionary[String], name: String) = {
    val value = rs(name)
    println(value)
    $(s":input[name='${name}']").`val`(value).trigger("onchange")
  }

  def refreshCheckboxView(phenotypeNames: List[String], idStr: String) = {
    val html = phenotypeNames.map { x =>
      label(marginRight := 15,
        input(`type` := "checkbox", checked, value := x, onclick := s"Utils.setColumns('${x}')", x)
      )
    }.mkString
    $(s"#${idStr}").html(html)
  }

  def refreshCheckboxView(map: SeqMap[String, String], idStr: String) = {
    val html = map.map { case (v, showV) =>
      label(marginRight := 15,
        input(`type` := "checkbox", checked, value := v, onclick := s"Utils.setColumns('${v}')", showV)
      )
    }.mkString
    $(s"#${idStr}").html(html)
  }

  def refreshCheckboxView(map: SeqMap[String, String], jq: JQuery, divId: String = "") = {
    val html = map.map { case (v, showV) =>
      label(marginRight := 15,
        input(`type` := "checkbox", checked, value := v, onclick := s"Utils.setColumns('${v}','${divId}')", showV)
      )
    }.mkString
    jq.html(html)
  }

  def getTextData(kind:String)={
    kind match {
      case VarTool.mRnaKind => TextData("mRNA and lncRNA", "Gene symbol",pm = "TPM")
      case VarTool.circRnaKind => TextData("circRNA", "circRNA",pm = "CPM")
      case VarTool.pathwayKind => TextData("Pathway", "Pathway",pm = "TPM")
      case VarTool.cellKind => TextData("Tissue/Cell origin", "Tissue/Cell origin",pm = "TPM")
    }
  }

}
